home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™94 / Talks & Papers / Michael D. Crawford↵ / Word Services SDK 1.0.5 / Writeswell Jr. Source / ObWind.c < prev    next >
Text File  |  1992-10-02  |  14KB  |  580 lines

  1. /* ObWind.c
  2.  * Routines to handle cWindow objects
  3.  * ©1992 Working Software, Inc.
  4.  * This source code is copyrighted.  Permission is granted to use the Word Services
  5.  * portion of the Writeswell Jr. source code in your own programs, but you 
  6.  * may not distribute the Writeswell Jr. word-processor code as a 
  7.  * commercial product.  If you modify the code, please do not call it 
  8.  * Writeswell Jr. (or Writeswell.)  This will ensure that people understand the 
  9.  * program and don’t have to deal with a number of different versions with 
  10.  * who-knows-what going on in the code.
  11.  * 
  12.  * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
  13.  * 24 Dec 91 Mike Crawford
  14.  */
  15. #include <AppleEvents.h>
  16. #include <AEObjects.h>
  17. #include <AEPackObject.h>
  18. #include <AERegistry.h>
  19. #include "AppEvents.h"
  20. #include "ObWind.h"
  21. #include "ObText.h"
  22. #include "ObOSpec.h"
  23. #include "Gripe.h"
  24.  
  25. OSErr WindGetDataHandler( AEDesc *tokenPtr,
  26.                         AppleEvent *theAppleEventPtr,
  27.                         AppleEvent *replyEventPtr,
  28.                         long refCon );
  29. OSErr WindSetDataHandler( AEDesc *tokenPtr,
  30.                         AppleEvent *theAppleEventPtr,
  31.                         AppleEvent *replyEventPtr,
  32.                         long refCon );
  33. OSErr WindCountHandler( AEDesc *tokenPtr,
  34.                         AppleEvent *theAppleEventPtr,
  35.                         AppleEvent *replyEventPtr,
  36.                         long refCon );
  37.  
  38. /* Given the the direct object of an event is a window token (or property thereof),
  39.  * do the requested event.
  40.  */
  41. OSErr DispatchWind( AEDesc *tokenPtr,
  42.                         AppleEvent *theAppleEventPtr,
  43.                         AppleEvent *replyEventPtr,
  44.                         long refCon )
  45. {
  46.     OSErr            err;
  47.     AEEventClass    theClass;
  48.     AEEventID        theID;
  49.     
  50.     /* This function is only for the Core suit.  Get the event ID from the appleEvent
  51.      */
  52.     
  53.     err = GetEventID( theAppleEventPtr, &theID );
  54.     
  55.     switch ( theID ){
  56.         case kAEGetData:
  57.             err = WindGetDataHandler( tokenPtr, theAppleEventPtr, replyEventPtr, refCon );
  58.             break;
  59.         case kAESetData:
  60.             err = WindSetDataHandler( tokenPtr, theAppleEventPtr, replyEventPtr, refCon );
  61.             break;
  62.         case kAECountElements:
  63.             err = WindCountHandler( tokenPtr, theAppleEventPtr, replyEventPtr, refCon );
  64.         default:
  65.             err = errAEEventNotHandled;
  66.             break;
  67.     }
  68.     
  69.     return noErr;
  70. }
  71.  
  72. /* The handlers for the various events */
  73.  
  74. /* Get Data */
  75.  
  76. OSErr WindGetDataHandler( AEDesc *tokenPtr,
  77.                         AppleEvent *theAppleEventPtr,
  78.                         AppleEvent *replyEventPtr,
  79.                         long refCon )
  80. {
  81.     WindowPtr        wp;
  82.     DescType        propCode;
  83.     WindTokenBody    **tokHdl;
  84.     AEDesc            replyValue;
  85.     Str255            tmpStr;
  86.     OSErr            err;
  87.  
  88.     /* Sanity check */
  89.     if ( tokenPtr->descriptorType != cWindow ){
  90.         Gripe( "\pGot wrong token type" );
  91.         return errAEEventNotHandled;
  92.     }
  93.  
  94.     tokHdl = (WindTokenBody**)(tokenPtr->dataHandle);
  95.     
  96.     wp = (*tokHdl)->theWindowPtr;
  97.     propCode = (*tokHdl)->propertyCode;
  98.     
  99.     if ( !wp ){
  100.         Gripe( "\pAttempting to get data for non-existent window" );
  101.         return errAENoSuchObject;
  102.     }
  103.  
  104.     switch ( propCode ){
  105.         case typeNull:
  106.             /* This is a magic number for "Not A Property".  I don't know if this
  107.              * is really kosher - gotta ask, but it is a convenience.
  108.              */
  109.             
  110.             /* Should return a string for object browsers */
  111.             Gripe( "\pTrying to GetData on a window object" );
  112.             return errAENoSuchObject;
  113.             break;
  114.         case pName:
  115.             GetWTitle( wp, tmpStr );
  116.                         
  117.             err = AECreateDesc( typeChar,
  118.                                 (Ptr)&(tmpStr[1]),
  119.                                 (Size)tmpStr[0],
  120.                                 &replyValue );
  121.             if ( err ){
  122.                 Gripe( "\pAECreateDesc failed" );
  123.                 return err;
  124.             }
  125.             break;
  126.         case pBounds:
  127.         case pClass:
  128.         case pHasTitleBar:
  129.         case pIndex:
  130.         case pIsModal:
  131.         case pIsResizable:
  132.         case pIsZoomed:
  133.         case pVisible:
  134.             Gripe( "\pGot a property type we do not yet implement" );
  135.             return errAENoSuchObject;
  136.             break;
  137.         default:
  138.             Gripe( "\pUnknown property type" );
  139.             return errAENoSuchObject;
  140.             break;
  141.     }
  142.     
  143.     /* At this point we have some kind of descriptor to stick in the reply */
  144.     
  145.     err = AEPutParamDesc( replyEventPtr,
  146.                             keyDirectObject,
  147.                             &replyValue );
  148.     if ( err ){
  149.         Gripe( "\pAEPutParamDesc failed" );
  150.         return err;
  151.     }
  152.     
  153.     err = AEDisposeDesc( &replyValue );
  154.     if ( err ){
  155.         Gripe( "\pAEDisposeDesc failed" );
  156.         return err;
  157.     }
  158.  
  159.     return noErr;
  160. }/* WindGetDataHandler */
  161.  
  162. /* Set Data */
  163.  
  164. OSErr WindSetDataHandler( AEDesc *tokenPtr,
  165.                         AppleEvent *theAppleEventPtr,
  166.                         AppleEvent *replyEventPtr,
  167.                         long refCon )
  168. {
  169.     WindowPtr        wp;
  170.     DescType        propCode;
  171.     WindTokenBody    **tokHdl;
  172.     AEDesc            newValue;
  173.     AEDesc            textValue;
  174.     OSErr            err;
  175.  
  176.     /* Sanity check */
  177.     if ( tokenPtr->descriptorType != cWindow ){
  178.         Gripe( "\pGot wrong token type" );
  179.         return errAEEventNotHandled;
  180.     }
  181.  
  182.     tokHdl = (WindTokenBody**)(tokenPtr->dataHandle);
  183.     
  184.     wp = (*tokHdl)->theWindowPtr;
  185.     propCode = (*tokHdl)->propertyCode;
  186.     
  187.     if ( !wp ){
  188.         Gripe( "\pAttempting to set data in non-existent window" );
  189.         return errAENoSuchObject;
  190.     }
  191.     
  192.     /* Get the value to set, whatever it is */
  193.     
  194.     err = AEGetParamDesc( theAppleEventPtr,
  195.                             keyAEData,
  196.                             typeWildCard,
  197.                             &newValue );
  198.     if ( err ){
  199.         Gripe( "\pAEGetParamDesc failed to get keyAEData" );
  200.         return err;
  201.     }                        
  202.  
  203.     switch ( propCode ){
  204.         case typeNull:
  205.             /* This is a magic number for "Not A Property".  I don't know if this
  206.              * is really kosher - gotta ask, but it is a convenience.
  207.              */
  208.             
  209.             /* I don't think it makes sense to Set Data on a window */
  210.             return errAEEventNotHandled;
  211.             break;
  212.         case pName:
  213.         
  214.             /* Make sure that the name is of type text */
  215.             err = AECoerceDesc( &newValue,
  216.                                 typePString,
  217.                                 &textValue );
  218.             if ( err ){
  219.                 Gripe( "\pAECoerceDesc failed to coerce to text" );
  220.                 return err;
  221.             }
  222.             
  223.             HLock( textValue.dataHandle );
  224.             
  225.             SetWTitle( wp, *(textValue.dataHandle) );
  226.                         
  227.             HUnlock( textValue.dataHandle );
  228.             
  229.             err = AEDisposeDesc( &textValue );
  230.             
  231.             if ( err ){
  232.                 Gripe( "\pAEDisposeDesc textValue failed" );
  233.                 return err;
  234.             }
  235.             
  236.             break;
  237.         case pBounds:
  238.         case pClass:
  239.         case pHasTitleBar:
  240.         case pIndex:
  241.         case pIsModal:
  242.         case pIsResizable:
  243.         case pIsZoomed:
  244.         case pVisible:
  245.             Gripe( "\pGot a property type we do not yet implement" );
  246.             return errAENoSuchObject;
  247.             break;
  248.         default:
  249.             Gripe( "\pUnknown property type" );
  250.             return errAENoSuchObject;
  251.             break;
  252.     }
  253.     
  254.     /* At this point we are done with the newValue descriptor */
  255.     
  256.     err = AEDisposeDesc( &newValue );
  257.     
  258.     if ( err ){
  259.         Gripe( "\pAEDisposeDesc newValue failed" );
  260.         return err;
  261.     }
  262.  
  263.     return noErr;
  264. }/* WindSetDataHandler */
  265.  
  266. /* Count Elements */
  267.  
  268. OSErr WindCountHandler( AEDesc *tokenPtr,
  269.                         AppleEvent *theAppleEventPtr,
  270.                         AppleEvent *replyEventPtr,
  271.                         long refCon )
  272. {
  273.     WindowPtr        wp;
  274.     DescType        propCode;
  275.     WindTokenBody    **tokHdl;
  276.     AEDesc            replyValue;
  277.     Str255            tmpStr;
  278.     AEDesc            elementClassDesc;
  279.     DescType        elementClass;
  280.     long            count;
  281.     OSErr            err;
  282.  
  283.     /* Sanity check */
  284.     if ( tokenPtr->descriptorType != cWindow ){
  285.         Gripe( "\pGot wrong token type" );
  286.         return errAEEventNotHandled;
  287.     }
  288.  
  289.     tokHdl = (WindTokenBody**)(tokenPtr->dataHandle);
  290.     
  291.     wp = (*tokHdl)->theWindowPtr;
  292.     propCode = (*tokHdl)->propertyCode;
  293.     
  294.     if ( !wp ){
  295.         Gripe( "\pAttempting to count elements for non-existent window" );
  296.         return errAENoSuchObject;
  297.     }
  298.  
  299.     /* Get the class of element that we want to count.  We could reasonably
  300.      * count the letters of the title property, for example.  Presently we
  301.      * only support counting the object specifier elements for the word services
  302.      * table checking method.
  303.      */
  304.     
  305.     err = AEGetParamDesc( theAppleEventPtr,
  306.                             keyAEObjectClass,
  307.                             typeType,
  308.                             &elementClassDesc );
  309.     if ( err ){
  310.         Gripe( "\pCould not get object class from Count Elements event" );
  311.         return err;
  312.     }
  313.     
  314.     elementClass = *(DescType*)(*elementClassDesc.dataHandle);
  315.     
  316.     switch ( propCode ){
  317.         case typeNull:
  318.             /* This is a magic number for "Not A Property".  I don't know if this
  319.              * is really kosher - gotta ask, but it is a convenience.
  320.              */
  321.             
  322.             /* In this case, we are counting the actual elements of the window.  This
  323.              * can be a text field or an object specifier.  We check to see what
  324.              * kind of element is desired, and call a function for that class to count
  325.              * it.
  326.              *
  327.              * We do not yet handle the case where we could have multiple containers.
  328.              */
  329.  
  330.             switch ( elementClass ){
  331.                 case cText:
  332.                     err = CountTextInWind( wp, &count );
  333.                     if ( err )
  334.                         return err;
  335.                     break;
  336.                 case typeObjectSpecifier:
  337.                     err = CountOSpecInWind( wp, &count );
  338.                     if ( err )
  339.                         return err;
  340.                     break;
  341.                 default:
  342.                     return errAENoSuchObject;
  343.                     break;
  344.             }
  345.             
  346.             err = AECreateDesc( typeLongInteger, (Ptr)&count, sizeof( count ), &replyValue );
  347.             if ( err ){
  348.                 Gripe( "\pAECreateDesc failed" );
  349.                 return err;
  350.             }
  351.             break;
  352.         case pName:
  353.         case pBounds:
  354.         case pClass:
  355.         case pHasTitleBar:
  356.         case pIndex:
  357.         case pIsModal:
  358.         case pIsResizable:
  359.         case pIsZoomed:
  360.         case pVisible:
  361.             /* In all of these cases, we are counting the elements of a property.
  362.              * This makes more sense than it might seem.  It is reasonable to count
  363.              * the letters in the name, for example.
  364.              */
  365.             Gripe( "\pGot a property type we do not yet implement" );
  366.             return errAENoSuchObject;
  367.             break;
  368.         default:
  369.             Gripe( "\pUnknown property type" );
  370.             return errAENoSuchObject;
  371.             break;
  372.     }
  373.     
  374.     /* At this point we have some kind of descriptor to stick in the reply */
  375.  
  376.     err = AEPutParamDesc( replyEventPtr,
  377.                             keyDirectObject,
  378.                             &replyValue );
  379.     if ( err ){
  380.         Gripe( "\pAEPutParamDesc failed" );
  381.         return err;
  382.     }
  383.     
  384.     err = AEDisposeDesc( &replyValue );
  385.     if ( err ){
  386.         Gripe( "\pAEDisposeDesc failed" );
  387.         return err;
  388.     }
  389.  
  390.     return noErr;
  391. }
  392.  
  393. /* Return a Window token given a null (application) token */
  394.  
  395. pascal OSErr WindFromNull(DescType desiredClass,
  396.                             const AEDesc *container,
  397.                             DescType containerClass,
  398.                             DescType form,
  399.                             const AEDesc *selectionData,
  400.                             AEDesc *theToken,
  401.                             long LongInt)
  402. {
  403.     AEDesc            longKeyData;
  404.     WindowPtr        wp;
  405.     long            count;
  406.     WindTokenBody    tokData;
  407.     OSErr            err;
  408.  
  409.     /* Check that the container is what we intend.  This should only happen if we
  410.      * installed the token handler incorrectly.
  411.      */
  412.  
  413.     if ( container->descriptorType != typeNull )
  414.         return errAEEventNotHandled;
  415.     
  416.     /* find the window based on the key form */
  417.     
  418.     switch ( form ){
  419.         case formAbsolutePosition:
  420.             /* Make sure we really have a type long descriptor */
  421.             err = AECoerceDesc( selectionData, typeLongInteger, &longKeyData );
  422.             if ( err ){
  423.                 Gripe( "\pAECoerceDesc failed" );
  424.                 return err;
  425.             }
  426.             
  427.             count = **(long**)(longKeyData.dataHandle);
  428.             
  429.             /* We're done with the descriptor created in the coercion */
  430.             
  431.             err = AEDisposeDesc( &longKeyData );
  432.             if ( err ){
  433.                 Gripe( "\pAEDisposeDesc failed" );
  434.                 return err;
  435.             }
  436.             
  437.             /* In our particular case, we can have at most one window, but we write 
  438.              * this in a general way for reusability... scan the window list for the
  439.              * window
  440.              */
  441.              
  442.             wp = FrontWindow();
  443.             
  444.             while( count > 1 && wp != (WindowPtr)NULL ){
  445.                 wp = (WindowPtr)((WindowPeek)wp)->nextWindow;
  446.             }
  447.             
  448.             if ( wp == (WindowPtr)NULL ){
  449.                 Gripe( "\pNo window found" );
  450.                 return errAENoSuchObject;
  451.             }
  452.             
  453.             /* Actually create the token that we return */
  454.             tokData.theWindowPtr = wp;
  455.             tokData.propertyCode = typeNull;        /* This means it's not a property */
  456.             
  457.             err = AECreateDesc( desiredClass, (Ptr)&tokData, sizeof( tokData ), theToken );
  458.             if ( err ){
  459.                 Gripe( "\pAECreateDesc failed to create a token" );
  460.                 return err;
  461.             }
  462.             
  463.             return noErr;
  464.             break;
  465.         case formRelativePosition:
  466.         case formTest:
  467.         case formRange:
  468.         case formPropertyID:
  469.         case formName:
  470.             return errAEEventNotHandled;    /* Flesh this out later */
  471.             break;
  472.         default:
  473.             Gripe( "\pGot unexpected key form" );
  474.             return errAEEventNotHandled;
  475.     }
  476.         
  477.     return noErr;
  478. }
  479.  
  480. /* Return a property token given a cWindow token.  This works for any property of a window */
  481.  
  482. pascal OSErr PropFromWind(DescType desiredClass,
  483.                             const AEDesc *container,
  484.                             DescType containerClass,
  485.                             DescType form,
  486.                             const AEDesc *selectionData,
  487.                             AEDesc *theToken,
  488.                             long LongInt)
  489. {
  490.     OSErr        err;
  491.     DescType    propType;
  492.  
  493.     /* Check that the container is what we intend.  This should only happen if we
  494.      * installed the token handler incorrectly.
  495.      */
  496.  
  497.     if ( container->descriptorType != cWindow )
  498.         return errAEEventNotHandled;
  499.  
  500.     if ( form != formPropertyID ){
  501.         Gripe( "\pExpected formPropertyID" );
  502.         return errAEEventNotHandled;
  503.     }
  504.  
  505.     propType = **( (DescType**)(selectionData->dataHandle) );
  506.  
  507.     /* All we really do here is shove the property type into the token, if we
  508.      * know about the property type
  509.      */
  510.  
  511.     switch ( propType ){
  512.         case pName:
  513.             break;
  514.         case pBounds:
  515.         case pClass:
  516.         case pHasTitleBar:
  517.         case pIndex:
  518.         case pIsModal:
  519.         case pIsResizable:
  520.         case pIsZoomed:
  521.         case pVisible:
  522.             Gripe( "\pGot a property type we do not yet implement" );
  523.             return errAENoSuchObject;
  524.             break;
  525.         default:
  526.             Gripe( "\pUnknown property type" );
  527.             return errAENoSuchObject;
  528.             break;
  529.     }
  530.  
  531.     /* All we do in the token is put the propType into it.  We can start with the
  532.      * container descriptor as it has some of the fields filled in already.
  533.      */
  534.     
  535.     err = AEDuplicateDesc( container, theToken );
  536.     if ( err ){
  537.         Gripe( "\pAEDuplicateDesc failed" );
  538.         return err;
  539.     }
  540.     
  541.     (*(WindTokenBody**)(theToken->dataHandle))->propertyCode = propType;
  542.     
  543.     return noErr;
  544. }
  545.  
  546. /*
  547.  * Descriptor packing routines
  548.  */
  549.  
  550. /* Create a formAbsolutePosition window descriptor */
  551.  
  552. OSErr BuildWindowSpecifier( AEDesc *specPtr, long whichWindow )
  553. {
  554.     AEDesc    nullDesc;
  555.     AEDesc    nullSpec;
  556.     AEDesc    whichDesc;
  557.     OSErr    err;
  558.     
  559.     /* Create the descriptor for the container (the application, or null) */
  560.  
  561.     err = AECreateDesc( typeNull, (Ptr)NULL, (Size)0, &nullDesc );
  562.     if ( err )
  563.         return err;
  564.     
  565.     /* Create the key data, which gives the window number */
  566.     
  567.     err = CreateOffsetDescriptor( whichWindow, &whichDesc );
  568.     if ( err )
  569.         return err;
  570.  
  571.     /* Create the Object Specifier for the window */
  572.     
  573.     err = CreateObjSpecifier( cWindow,
  574.                                 &nullDesc,
  575.                                 formAbsolutePosition,
  576.                                 &whichDesc,
  577.                                 true,                    /* Dispose of input descriptors */
  578.                                 specPtr );                /* specPtr is the value we return */
  579.     return err;
  580. }